package mips.instructions;

import java.util.HashMap;
import java.util.Map;

import mips.structure.MipsInstr;
import mips.value.Immediate;
import mips.value.MipsValue;

public class Branch extends MipsInstr {
    public MipsValue op1;
    public MipsValue op2;
    public String label1;
    public String label2;
    public BranchType type;

    public Branch(String type, MipsValue op1, MipsValue op2, String label1, String label2) {
        this.op1 = op1;
        this.label1 = label1;
        this.label2 = label2;
        this.op2 = op2;
        this.type = map.get(type);
    }

    public enum BranchType {
        beq,
        bne,
        ble,
        bgt,
        blt,
        bge
    }

    private Map<String, BranchType> map = new HashMap<>();

    {
        map.put("==", BranchType.beq);
        map.put("!=", BranchType.bne);
        map.put("<=", BranchType.ble);
        map.put(">=", BranchType.bgt);
        map.put("<", BranchType.blt);
        map.put(">", BranchType.bge);
    }

    public String toBeqString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() == ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "beq " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "beq " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    public String toBneString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() != ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "bne " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "bne " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    public String toBleString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() <= ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "bgt " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "ble " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    public String toBgtString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() > ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "ble " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "bgt " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    public String toBltString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() < ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "bge " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "blt " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    public String toBgeString() {
        if (op1 instanceof Immediate && op2 instanceof Immediate) {
            if (((Immediate) op1).getValue() >= ((Immediate) op2).getValue()) {
                return "j " + label1;
            } else {
                return "j " + label2;
            }
        } else if (op1 instanceof Immediate) {
            return "blt " + op2 + ", " + op1 + ", " + label1 + "\nj " + label2;
        } else {
            return "bge " + op1 + ", " + op2 + ", " + label1 + "\nj " + label2;
        }
    }

    @Override
    public String toString() {
        if (type == BranchType.beq) {
            return toBeqString();
        } else if (type == BranchType.bne) {
            return toBneString();
        } else if (type == BranchType.ble) {
            return toBleString();
        } else if (type == BranchType.bgt) {
            return toBgtString();
        } else if (type == BranchType.blt) {
            return toBltString();
        } else if (type == BranchType.bge) {
            return toBgeString();
        } else {
            return null;
        }
    }

}
